package org.example.method;

import static cn.hutool.http.HttpUtil.createRequest;

import cn.hutool.core.util.IdUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.util.EntityUtils;
import org.example.pojo.SampleResult;
import org.example.pojo.TraceIndex;

@Slf4j
public class test {
  private CloseableHttpAsyncClient httpClient;
  private HttpPost httpRequest;
  private Future<HttpResponse> lastRequest;
  private final ObjectMapper objectMapper = new ObjectMapper();
  // 创建线程池,策略选用超出阻塞队列的任务交由主线程执行
  private static final ThreadPoolExecutor executor =
      new ThreadPoolExecutor(
          6,
          12,
          2,
          TimeUnit.MINUTES,
          new LinkedBlockingQueue<>(),
          new ThreadPoolExecutor.CallerRunsPolicy());

  private HttpPost createRequest(URL url) throws URISyntaxException {
    RequestConfig defaultRequestConfig =
        RequestConfig.custom()
            .setConnectTimeout(1000)
            .setSocketTimeout(3000)
            .setConnectionRequestTimeout(100)
            .build();

    HttpPost currentHttpRequest = new HttpPost(url.toURI());
    currentHttpRequest.setHeader("Content-Type", "application/json");
    currentHttpRequest.setConfig(defaultRequestConfig);
    log.debug("Created traceSender with url: {}", url);
    return currentHttpRequest;
  }

  public void setupTest() throws Exception {
    // Create I/O reactor configuration
    IOReactorConfig ioReactorConfig =
        IOReactorConfig.custom()
            .setIoThreadCount(1)
            .setConnectTimeout(1000)
            .setSoTimeout(3000)
            .build();
    // Create a custom I/O reactor
    ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);

    // Create a connection manager with custom configuration.
    PoolingNHttpClientConnectionManager connManager =
        new PoolingNHttpClientConnectionManager(ioReactor);

    httpClient =
        HttpAsyncClientBuilder.create()
            .setConnectionManager(connManager)
            .setMaxConnPerRoute(4)
            .setMaxConnTotal(4)
            .setUserAgent("ApacheJMeter" + "1.0")
            .disableCookieManagement()
            .disableConnectionState()
            .build();
    httpRequest =
        createRequest(new URL("http://localhost:8086/load/api/internal/trace/index/save"));
    httpRequest.setHeader(
        "Cookie",
        "think_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjdXJyZW50VGltZU1pbGxpcyI6MTcyMzg4OTcwNTk1MywiZXhwIjoxNzI0NzUzNzA1LCJ1c2VySWQiOiIxNzRhMTUifQ.qpYJ_KS2Htmk_KDDHB1muzfFPc7VeTQw-iPvYBjJWUY");
    httpClient.start();
  }

  @SneakyThrows
  private void digui(List<TraceIndex> list, SampleResult sampleResult) {
    // 设置线程耗时-业务耗时
    if (sampleResult.isShouldSampleTrace() && sampleResult.getTraceId() != null) {
      list.add(toTraceIndex(sampleResult));
    }
    if (sampleResult.getSubResults() != null) {
      for (SampleResult subResult : sampleResult.getSubResults()) {
        digui(list, subResult);
      }
    }
  }

  public void handleSampleResults(List<SampleResult> sampleResults) {
    CompletableFuture.runAsync(
            () -> {
              List<TraceIndex> list = new ArrayList<>();
              if (sampleResults == null) {
                return;
              }
              for (SampleResult sampleResult : sampleResults) {
                digui(list, sampleResult);
              }
              // 等待所有任务执行完成
              sendTraceIndices(list);
            },
            executor)
        .whenComplete(
            (result, throwable) -> {
              if (throwable != null) {
                throw new RuntimeException(throwable);
              }
            });
  }

  public void handleSampleResults2(List<SampleResult> sampleResults) {
    List<TraceIndex> list = new ArrayList<>();
    if (sampleResults == null) {
      return;
    }
    for (SampleResult sampleResult : sampleResults) {
      digui(list, sampleResult);
    }
    sendTraceIndices(list);
  }

  private TraceIndex toTraceIndex(SampleResult sampleResult) {
    TraceIndex traceIndex = new TraceIndex();
    traceIndex.setExecutionId(IdUtil.getSnowflakeNextId());
    traceIndex.setContainerId(IdUtil.getSnowflakeNextIdStr());
    traceIndex.setThreadGroup(sampleResult.getThreadGroup());
    traceIndex.setParent("");
    traceIndex.setLabel("");
    traceIndex.setStartMillSeconds(2L);
    traceIndex.setEndMillSeconds(4L);
    traceIndex.setDurationMillSeconds(2L);
    traceIndex.setStatus(sampleResult.isSuccessful() ? "SUCCESS" : "FAIL");
    traceIndex.setErrorType("");
    traceIndex.setErrorMessage("");
    traceIndex.setTraceId(sampleResult.getTraceId());
    return traceIndex;
  }

  private static String getBody(final HttpResponse response) {
    String body = "";
    try {
      if (response != null && response.getEntity() != null) {
        body = EntityUtils.toString(response.getEntity());
      }
    } catch (Exception e) { // NOSONAR
      // NOOP
    }
    return body;
  }

  private void sendTraceIndices(List<TraceIndex> traceIndices) {
    if (traceIndices.isEmpty()) {
      return;
    }
    // try {
    //   String data = objectMapper.writeValueAsString(traceIndices);
    //   httpRequest.setEntity(new StringEntity(data, StandardCharsets.UTF_8));
    //   lastRequest =
    //       httpClient.execute(
    //           httpRequest,
    //           new FutureCallback<HttpResponse>() {
    //             @Override
    //             public void completed(final HttpResponse response) {
    //               int code = response.getStatusLine().getStatusCode();
    //               if (MetricUtils.isSuccessCode(code)) {
    //                 if (log.isDebugEnabled()) {
    //                   log.debug("Success, number of metrics written: {}", traceIndices.size());
    //                 }
    //               } else {
    //                 log.error(
    //                     "Error send trace indices to load-server, responseCode: {}, responseBody:
    // {}",
    //                     code,
    //                     getBody(response));
    //               }
    //             }
    //
    //             @Override
    //             public void failed(final Exception ex) {
    //               log.error("failed to send trace indices to load-server.", ex);
    //             }
    //
    //             @Override
    //             public void cancelled() {
    //               log.warn("Request to load-server was cancelled");
    //             }
    //           });
    // } catch (Exception ex) {
    //   log.error(ex.getMessage(), ex);
    // }
  }

  public static void main(String[] args) throws Exception {
    List<SampleResult> sampleResults = new ArrayList<>();
    generate(sampleResults);
    test test = new test();
    // test.setupTest();
    test.handleSampleResults(sampleResults);
    if (args != null) {
      test.handleSampleResults2(sampleResults);
    }
  }

  private static void generate(List<SampleResult> sampleResults) {
    SampleResult sampleResult = new SampleResult().setSubResults(null);
    for (int i = 0; i < 500; i++) {
      sampleResults.add(sampleResult);
    }
  }
}
